﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
namespace Nirvana
{
    [Serializable]
    public sealed class CheckMaterial
    {
        [Tooltip("Check whether the material is duplication.")]
        [SerializeField]
        private bool checkDuplication;

        private enum MainTextureMode
        {
            [EnumLabel("Not Check")]
            NotCheck,
            [EnumLabel("Check")]
            Check
        }

        [SerializeField]
        [EnumLabel]
        [Tooltip("The main texture check mode.")]
        private MainTextureMode mainTextureMode;

        [Tooltip("The valid shaders for check.")]
        [SerializeField]
        private string[] validShaderNames;

        [SerializeField]
        [Tooltip("The invalid shaders for check.")]
        private string[] invalidShaderNames;

        [SerializeField]
        [Tooltip("The valid keywords for check.")]
        private string[] validKeywords;
        [SerializeField]
        [Tooltip("The invalid keywords for check.")]
        private string[] invalidKeywords;

        private Dictionary<MaterialInspectorData, Material> matMap = new Dictionary<MaterialInspectorData, Material>();

        public void Clear()
        {
            matMap.Clear();
        }

        public void CheckMaterials(AssetCheckReport report, Material mat)
        {
            if (this.checkDuplication)
            {
                var data = GetMaterialProperies(mat);
                if (matMap.ContainsKey(data))
                {
                    report.ShowWarnInfo("This material <b><color=orange>{0}</color></b> is duplicate with <b><color=orange>{1}</color></b>.", mat.name,matMap[data].name);
                }
                else
                {
                    matMap.Add(data, mat);
                }
            }

            if (this.mainTextureMode == MainTextureMode.Check && mat.mainTexture == null)
            {
                report.ShowWarnInfo("The main texture of the material <b><color=orange>{0}</color></b> is null.",mat.name);
            }

            if (this.validShaderNames != null && this.validShaderNames.Length > 0 && Array.IndexOf<string>(this.validShaderNames, mat.shader.name) < 0)
            {
                report.ShowWarnInfo("The material <b><color=orange>{0}</color></b> has an invalid shader <b><color=orange>{1}</color></b>.",mat.name,mat.shader.name);
            }

            if (this.invalidShaderNames != null && this.invalidShaderNames.Length > 0 && Array.IndexOf<string>(this.invalidShaderNames, mat.shader.name) >= 0)
            {
                report.ShowWarnInfo("The material <b><color=orange>{0}</color></b> has an invalid shader <b><color=orange>{1}</color></b>.",
                    mat.name,
                    mat.shader.name
                );
            }


            if (this.validKeywords != null && this.validKeywords.Length > 0)
            {
                foreach (string k in this.validKeywords)
                {
                    if (Array.IndexOf<string>(mat.shaderKeywords, k) < 0)
                    {
                        report.ShowWarnInfo("The material <b><color=orange>{0}</color></b> does not has the keyword: <b><color=orange>{1}</color></b>.", mat.name,k);
                    }
                }
            }

            if (this.invalidKeywords != null && this.invalidKeywords.Length > 0)
            {
                foreach (string k in this.invalidKeywords)
                {
                    if (Array.IndexOf<string>(mat.shaderKeywords, k) >= 0)
                    {
                        report.ShowWarnInfo("The material <b><color=orange>{0}</color></b> can not has the keyword: <b><color=orange>{1}</color></b>.", mat.name,k);
                    }
                }
            }
        }

        private MaterialInspectorData GetMaterialProperies(Material mat)
        {
            var mdata = new MaterialInspectorData();
            mdata.shader = mat.shader;
            mdata.shaderKeywords = mat.shaderKeywords;
            mdata.globalIlluminationFlags = mat.globalIlluminationFlags;
            mdata.enableInstancing = mat.enableInstancing;
            mdata.doubleSidedGI = mat.doubleSidedGI;
            mdata.renderQueue = mat.renderQueue;
            mdata.stringTagMap = new Dictionary<string, string>();
            // material 菜单debug项查看
            var serializedObject = new SerializedObject(mat);
            var stringTagMap = serializedObject.FindProperty("stringTagMap");
            if (stringTagMap != null && stringTagMap.isArray)
            {
                for (int i = 0; i < stringTagMap.arraySize; i++)
                {
                    var arrayElementAtIndex = stringTagMap.GetArrayElementAtIndex(i);
                    var first = arrayElementAtIndex.FindPropertyRelative("first");
                    var second = arrayElementAtIndex.FindPropertyRelative("second");
                    mdata.stringTagMap.Add(first.stringValue, second.stringValue);
                }
            }
            mdata.disabledShaderPasses = new List<int>();
            var disabledShaderPasses = serializedObject.FindProperty("disabledShaderPasses");
            if (disabledShaderPasses != null && disabledShaderPasses.isArray)
            {
                for (int j = 0; j < disabledShaderPasses.arraySize; j++)
                {
                    var arrayElementAtIndex = disabledShaderPasses.GetArrayElementAtIndex(j);
                    mdata.disabledShaderPasses.Add(arrayElementAtIndex.intValue);
                }
            }
            mdata.textureEnvs = new Dictionary<string, TextureEnvs>();
            mdata.floatsProperies = new Dictionary<string, float>();
            mdata.colorsProperies = new Dictionary<string, Color>();
            mdata.vectorProperies = new Dictionary<string, Vector4>();

            SerializedProperty m_SavedProperties = serializedObject.FindProperty("m_SavedProperties");
            if (m_SavedProperties != null)
            {
                var m_TexEnvs = m_SavedProperties.FindPropertyRelative("m_TexEnvs");
                if (m_TexEnvs != null && m_TexEnvs.isArray)
                {
                    for (int k = 0; k < m_TexEnvs.arraySize; k++)
                    {
                        SerializedProperty arrayElement = m_TexEnvs.GetArrayElementAtIndex(k);
                        SerializedProperty first = arrayElement.FindPropertyRelative("first");
                        SerializedProperty second = arrayElement.FindPropertyRelative("second");
                        SerializedProperty m_Texture = second.FindPropertyRelative("m_Texture");
                        SerializedProperty m_Scale = second.FindPropertyRelative("m_Scale");
                        SerializedProperty m_Offset = second.FindPropertyRelative("m_Offset");
                        TextureEnvs textureData = new TextureEnvs();
                        textureData.mainTexture = m_Texture.objectReferenceValue as Texture;
                        textureData.mainTextureScale = m_Scale.vector2Value;
                        textureData.mainTextureOffset = m_Offset.vector2Value;
                        mdata.textureEnvs.Add(first.stringValue, textureData);
                    }

                }

                var m_Floats = m_SavedProperties.FindPropertyRelative("m_Floats");
                if (m_Floats != null && m_Floats.isArray)
                {
                    for (int l = 0; l < m_Floats.arraySize; l++)
                    {
                        SerializedProperty arrayElement = m_Floats.GetArrayElementAtIndex(l);
                        SerializedProperty first = arrayElement.FindPropertyRelative("first");
                        SerializedProperty second = arrayElement.FindPropertyRelative("second");
                        mdata.floatsProperies.Add(first.stringValue, second.floatValue);
                    }
                }

                var m_Colors = m_SavedProperties.FindPropertyRelative("m_Colors");
                if (m_Colors != null && m_Colors.isArray)
                {
                    for (int m = 0; m < m_Colors.arraySize; m++)
                    {
                        SerializedProperty arrayElement = m_Colors.GetArrayElementAtIndex(m);
                        SerializedProperty first = arrayElement.FindPropertyRelative("first");
                        SerializedProperty second = arrayElement.FindPropertyRelative("second");
                        mdata.colorsProperies.Add(first.stringValue, second.colorValue);
                    }
                }

                var m_Vector = m_SavedProperties.FindPropertyRelative("m_Vector");
                if (m_Vector != null && m_Vector.isArray)
                {
                    for (int n = 0; n < m_Vector.arraySize; n++)
                    {
                        SerializedProperty arrayElement = m_Vector.GetArrayElementAtIndex(n);
                        SerializedProperty first = arrayElement.FindPropertyRelative("first");
                        SerializedProperty second = arrayElement.FindPropertyRelative("second");
                        mdata.vectorProperies.Add(first.stringValue, second.vector4Value);
                    }
                }
            }
            return mdata;
        }


        private class MaterialInspectorData
        {
            public string[] shaderKeywords { get; set; }
            public bool enableInstancing { get; set; }
            public bool doubleSidedGI { get; set; }
            public MaterialGlobalIlluminationFlags globalIlluminationFlags { get; set; }
            public int renderQueue { get; set; }

            public Shader shader { get; set; }
            public Dictionary<string, string> stringTagMap;
            public List<int> disabledShaderPasses;
            public Dictionary<string, float> floatsProperies;

            public Dictionary<string, Color> colorsProperies;

            public Dictionary<string, Vector4> vectorProperies;
            public Dictionary<string, TextureEnvs> textureEnvs;



        }

        private class TextureEnvs
        {
            public Texture mainTexture { get; set; }
            public Vector2 mainTextureScale { get; set; }
            public Vector2 mainTextureOffset { get; set; }
            public override int GetHashCode()
            {
                int hash = 0;
                if (this.mainTexture != null)
                {
                    hash = 397 * hash ^ this.mainTexture.GetHashCode();
                    hash = 397 * hash ^ this.mainTextureScale.GetHashCode();
                    hash = 397 * hash ^ this.mainTextureOffset.GetHashCode();
                }
                return hash;
            }
        }


    }
}
